using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.Json;
using Spectre.Console;

namespace Generator.Commands;

public class AsciiCastOut : IAnsiConsoleOutput
{
    private sealed class AsciiCastWriter : TextWriter
    {
        private readonly TextWriter _wrappedTextWriter;
        private readonly StringBuilder _builder = new StringBuilder();
        private int? _firstTick;

        public AsciiCastWriter(TextWriter wrappedTextWriter)
        {
            _wrappedTextWriter = wrappedTextWriter;
        }

        public override void Write(string? value)
        {
            if (value == null)
            {
                return;
            }

            Append(value);
            _wrappedTextWriter.Write(value);
            base.Write(value);
        }

        public override Encoding Encoding => _wrappedTextWriter.Encoding;

        private void Append(string value)
        {
            var tick = 0m;
            if (_firstTick.HasValue)
            {
                tick = Environment.TickCount - _firstTick.Value;
            }
            else
            {
                _firstTick = Environment.TickCount;
            }

            tick /= 1000m;

            _builder.Append('[')
                .AppendFormat(CultureInfo.InvariantCulture, "{0}", tick)
                .Append(", \"o\", \"").Append(JsonEncodedText.Encode(value)).AppendLine("\"]");
        }

        public string GetJsonAndClearBuffer()
        {
            var json = _builder.ToString();

            // reset the buffer and also reset the first tick count
            _builder.Clear();
            _firstTick = null;
            return json;
        }
    }

    private readonly IAnsiConsoleOutput _wrappedAnsiConsole;
    private readonly AsciiCastWriter _asciiCastWriter;

    public AsciiCastOut(IAnsiConsoleOutput wrappedAnsiConsole)
    {
        _wrappedAnsiConsole = wrappedAnsiConsole ?? throw new ArgumentNullException(nameof(wrappedAnsiConsole));
        _asciiCastWriter = new AsciiCastWriter(_wrappedAnsiConsole.Writer);
    }

    public TextWriter Writer => _asciiCastWriter;

    public bool IsTerminal => _wrappedAnsiConsole.IsTerminal;

    public int Width => _wrappedAnsiConsole.Width;

    public int Height => _wrappedAnsiConsole.Height;

    public void SetEncoding(Encoding encoding)
    {
        _wrappedAnsiConsole.SetEncoding(encoding);
    }

    public string GetCastJson(string title, int? width = null, int? height = null)
    {
        var header = $"{{\"version\": 2, \"width\": {width ?? _wrappedAnsiConsole.Width}, \"height\": {height ?? _wrappedAnsiConsole.Height}, \"title\": \"{JsonEncodedText.Encode(title)}\", \"env\": {{\"TERM\": \"Spectre.Console\"}}}}";
        return $"{header}{Environment.NewLine}{_asciiCastWriter.GetJsonAndClearBuffer()}{Environment.NewLine}";
    }
}